#pragma once
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <random>
#include <sstream>
#include <iomanip>
#include <atomic>
#include <sqlite3.h>
#include <cstring>
#include <cerrno>
#include <sys/stat.h>
#include "mq_logger.hpp"
namespace bitmq
{
    class SqliteHelper
    {
    public:
        typedef int (*SqliteCallBack)(void *, int, char **, char **);
        SqliteHelper(const std::string dbfile)
            : _dbfile(dbfile), _handler(nullptr)
        {
        }
        bool open(int safe_level = SQLITE_OPEN_FULLMUTEX)
        {
            int ret = sqlite3_open_v2(_dbfile.c_str(), &_handler, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | safe_level, nullptr);
            if (ret != SQLITE_OK)
            {
                ELOG("创建/打开sqlite数据库失败: %s", sqlite3_errmsg(_handler));
                return false;
            }
            return true;
        }
        bool exec(const std::string &sql, SqliteCallBack cb, void *arg)
        {
            int ret = sqlite3_exec(_handler, sql.c_str(), cb, arg, nullptr);
            if (ret != SQLITE_OK)
            {
                ELOG("执行语句失败: %s", sqlite3_errmsg(_handler));
                return false;
            }
            return true;
        }
        void close()
        {
            if (_handler)
                sqlite3_close_v2(_handler);
        }
        ~SqliteHelper()
        {
        }

    private:
        sqlite3 *_handler;
        std::string _dbfile;
    };
    class StrHelper
    {
    public:
        static size_t split(const std::string& as, const std::string& vd, std::vector<std::string> &result)
        {
            size_t pos = 0, srt = 0;
            while (srt < as.size())
            {
                pos = as.find(vd, srt);
                if (pos == std::string::npos)
                {
                    result.push_back(as.substr(srt));
                    return result.size();
                }
                if (pos == srt)
                {
                    srt = pos + vd.size();
                    continue;
                }
                result.push_back(as.substr(srt, pos - srt));
                srt = pos + vd.size();
            }
            return result.size();
        }
    };
    class UUIDHelper
    {
    public:
        static std::string uuid()
        {
            // 生成随机数
            std::random_device as;
            // 以as为种子生成伟随机数
            std::mt19937_64 gen(as());
            // 生成0-255随机数
            std::uniform_int_distribution<int> aq(0, 255);
            std::stringstream ss;
            // 生成8次0-255数并依次转化为俩宽度的16进制字符
            for (int i = 0; i < 8; i++)
            {
                ss << std::setw(2) << std::setfill('0') << std::hex << aq(gen);
                if (i == 3 || i == 5 || i == 7)
                {
                    ss << '-';
                }
            }
            static std::atomic<size_t> qw(1);
            size_t num = qw.fetch_add(1);
            for (int i = 7; i >= 0; i--)
            {
                ss << std::setw(2) << std::setfill('0') << std::hex << ((num >> (i * 8)) & 0xff);
                if (i == 6)
                    ss << "-";
            }
            return ss.str();
        }
    };
    class FileHelper
    {
    public:
        FileHelper(const std::string pathname)
            : _pathname(pathname)
        {
        }
        bool exists()
        {
            struct stat tr;
            int ret = stat(_pathname.c_str(), &tr);
            return ret == 0;
        }
        size_t size()
        {
            struct stat tr;
            int ret = stat(_pathname.c_str(), &tr);
            if (ret < 0)
            {

                return 0;
            }
            return tr.st_size;
        }
        bool read(char *body, size_t offset, size_t len)
        {
            std::ifstream as(_pathname, std::ios::binary | std::ios::in);
            if (as.is_open() == false)
            {
                ELOG("%s 文件打开失败！！", _pathname.c_str());
                return false;
            }
            as.seekg(offset, std::ios::beg);
            as.read(body, len);
            if (as.good() == false)
            {
                ELOG("%s 文件读取数据失败！！", _pathname.c_str());
                as.close();
                return false;
            }
            as.close();
            return true;
        }
        bool read(std::string &body)
        {
            size_t ji = this->size();
            body.resize(ji);
            return read(&body[0], 0, ji);
        }
        bool write(const char *body, size_t offset, size_t len)
        {
            std::fstream as(_pathname, std::ios::binary | std::ios::in | std::ios::out);
            if (as.is_open() == false)
            {
                ELOG("%s 文件打开失败！！", _pathname.c_str());
                return false;
            }
            as.seekg(offset, std::ios::beg);
            as.write(body, len);
            if (as.good() == false)
            {
                ELOG("%s 文件写入数据失败！！", _pathname.c_str());
                as.close();
                return false;
            }
            as.close();
            return true;
        }
        bool write(const std::string &body)
        {
            return write(body.c_str(), 0, body.size());
        }
        static bool FileCreat(const std::string &filename)
        {
            std::fstream as(filename,std::ios::out|std::ios::binary);
            if(as.is_open()==false)
            {
                  ELOG("%s 文件创建失败！", filename.c_str());
                return false;
            }
            as.close();
            return true;
        }
        static bool FileDelete(const std::string &filename)
        {
            return (::remove(filename.c_str())==0);
        }
        static bool DirectorCreat(const std::string &path)
        {
            size_t pos,srt=0;
            while(srt<path.size())
            {
                pos=path.find("/",srt);
                if(pos==std::string::npos)
                {
                    return (mkdir(path.c_str(),0775)==0);
                }
                std::string aq=path.substr(0,pos);
                 int ret = mkdir(aq.c_str(), 0775);
                 if(ret!=0&&errno != EEXIST)
                 {
                    ELOG("创建目录 %s 失败: %s", aq.c_str(), strerror(errno));
                    return false;
                 }
                 srt=pos+1;
            }
            return true;
        }
        static bool DirectorDelete(const std::string &path)
        {
            std::string cmd="rm -rf "+path;
            return (system(cmd.c_str())!=-1);
        }
        bool rename(const std::string &nname)
        {
            return ::rename(_pathname.c_str(),nname.c_str())==0;
        }
        static std::string ParentDirector(const std::string &filename)
        {
            size_t pos=filename.find_last_of("/");
            if(pos==std::string::npos)
            {
                return "./";
            }
            std::string as=filename.substr(0,pos);
            return as;
        }

    private:
        std::string _pathname;
    };
}